package edu.calvin.djs32.cs214.interpreters.calculator;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;

import edu.calvin.cs214.hobbes2008.ApplicationTIR;
import edu.calvin.cs214.hobbes2008.IdentifierTIR;
import edu.calvin.cs214.hobbes2008.IntegerTIR;
import edu.calvin.cs214.hobbes2008.StringTIR;
import edu.calvin.cs214.hobbes2008.TupleTIR;


public class CalculatorTest {
	private Calculator myCalculator;
	@Before
	public void setUp() {
		myCalculator = new Calculator();
	}
	
	@Test
	public void ShouldReturnIntegerUntouched(){
		assertEquals(new IntegerTIR(1), myCalculator.visitInteger(new IntegerTIR(1)));
		assertEquals(new IntegerTIR(2), myCalculator.visitInteger(new IntegerTIR(2)));
		assertEquals(new IntegerTIR(0x123f), myCalculator.visitInteger(new IntegerTIR(0x123f)));
	}
	
	@Test
	public void ShouldReturnStringUntoucher(){
		assertEquals(new StringTIR("foo"), myCalculator.visitString(new StringTIR("foo")));
		assertEquals(new StringTIR("bar"), myCalculator.visitString(new StringTIR("bar")));
		assertEquals(new StringTIR("foo bar"), myCalculator.visitString(new StringTIR("foo bar")));
	}
	
	@Test
	public void ShouldReturnTupleUntouched(){
		assertEquals(new TupleTIR(new IntegerTIR(1), new IntegerTIR(2)), myCalculator.visitTuple(new TupleTIR(new IntegerTIR(1), new IntegerTIR(2))));
	}
	
	@Test
	public void ShouldDoApplicationTIRs(){
		assertEquals("1+2 should be 3", new IntegerTIR(3), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("+"),
			        new TupleTIR(new IntegerTIR(1), new IntegerTIR(2)))));
		assertEquals("4+5 should be 9", new IntegerTIR(9), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("+"),
			        new TupleTIR(new IntegerTIR(4), new IntegerTIR(5)))));
		assertEquals("10+12 should be 22", new IntegerTIR(22), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("+"),
			        new TupleTIR(new IntegerTIR(10), new IntegerTIR(12)))));
		assertEquals("2*3 should be 6", new IntegerTIR(6), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("*"),
			        new TupleTIR(new IntegerTIR(3), new IntegerTIR(2)))));
		assertEquals("3*4 should be 12", new IntegerTIR(12), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("*"),
			        new TupleTIR(new IntegerTIR(3), new IntegerTIR(4)))));
		assertEquals("10*3 should be 30", new IntegerTIR(30), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("*"),
			        new TupleTIR(new IntegerTIR(10), new IntegerTIR(3)))));
		assertEquals("10-3 should be 7", new IntegerTIR(7), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("-"),
			        new TupleTIR(new IntegerTIR(10), new IntegerTIR(3)))));
		assertEquals("15-3 should be 12", new IntegerTIR(12), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("-"),
			        new TupleTIR(new IntegerTIR(15), new IntegerTIR(3)))));
		assertEquals("4-3 should be 1", new IntegerTIR(1), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("-"),
			        new TupleTIR(new IntegerTIR(4), new IntegerTIR(3)))));
		assertEquals("6/3 should be 2", new IntegerTIR(2), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("/"),
			        new TupleTIR(new IntegerTIR(6), new IntegerTIR(3)))));
		assertEquals("3/3 should be 1", new IntegerTIR(1), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("/"),
			        new TupleTIR(new IntegerTIR(3), new IntegerTIR(3)))));
		assertEquals("9/3 should be 3", new IntegerTIR(3), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("/"),
			        new TupleTIR(new IntegerTIR(9), new IntegerTIR(3)))));
	}
	@Test
	public void ShouldDoNestedArithmetic(){
		assertEquals(new IntegerTIR(45), myCalculator.visitApplication(
				  new ApplicationTIR(
				    new IdentifierTIR("*"),
				    new TupleTIR(
				      new ApplicationTIR(
				        new IdentifierTIR("+"),
				        new TupleTIR(new IntegerTIR(2), new IntegerTIR(3))),
				      new ApplicationTIR(
				        new IdentifierTIR("/"),
				        new TupleTIR(new IntegerTIR(36), new IntegerTIR(4))
				      )))));
		
	}
	
	@Test
	public void ShouldDoEvenMore(){
		assertEquals("abs(1) should be 1", new IntegerTIR(1), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("abs"),
			        new TupleTIR(new IntegerTIR(1)))));
		assertEquals("abs(-1) should be 1", new IntegerTIR(1), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("abs"),
			        new TupleTIR(new IntegerTIR(-1)))));
		assertEquals("abs(-4) should be 4", new IntegerTIR(4), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("abs"),
			        new TupleTIR(new IntegerTIR(-4)))));
		
		assertEquals("max of 3 and 4 should be 4", new IntegerTIR(4), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("max"),
			        new TupleTIR(new IntegerTIR(3), new IntegerTIR(4)))));
		assertEquals("max of 5 and 5 should be 5", new IntegerTIR(5), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("max"),
			        new TupleTIR(new IntegerTIR(5), new IntegerTIR(5)))));
		assertEquals("max of -3 and -4 should be -3", new IntegerTIR(-3), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("max"),
			        new TupleTIR(new IntegerTIR(-3), new IntegerTIR(-4)))));
		
		assertEquals("min of 3 and 4 should be 4", new IntegerTIR(3), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("min"),
			        new TupleTIR(new IntegerTIR(3), new IntegerTIR(4)))));
		assertEquals("min of 5 and 5 should be 5", new IntegerTIR(5), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("min"),
			        new TupleTIR(new IntegerTIR(5), new IntegerTIR(5)))));
		assertEquals("min of -3 and -4 should be -3", new IntegerTIR(-4), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("min"),
			        new TupleTIR(new IntegerTIR(-3), new IntegerTIR(-4)))));
		
		assertEquals("square of 3 should be 9", new IntegerTIR(9), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("square"),
			        new TupleTIR(new IntegerTIR(3)))));
		assertEquals("square of 5 should be 25", new IntegerTIR(25), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("square"),
			        new TupleTIR(new IntegerTIR(5)))));
		assertEquals("square of -3 should be 9", new IntegerTIR(9), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("square"),
			        new TupleTIR(new IntegerTIR(-3)))));
		
		assertEquals("sqrt of 9 should be 3", new IntegerTIR(3), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("sqrt"),
			        new TupleTIR(new IntegerTIR(9)))));
		assertEquals("sqrt of 25 should be 5", new IntegerTIR(5), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("sqrt"),
			        new TupleTIR(new IntegerTIR(25)))));
		assertEquals("sqrt of 2 should be 1", new IntegerTIR(1), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("sqrt"),
			        new TupleTIR(new IntegerTIR(2)))));
		
		assertEquals("2^3 should be 8", new IntegerTIR(8), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("pow"),
			        new TupleTIR(new IntegerTIR(2), new IntegerTIR(3)))));
		assertEquals("2^4 should be 16", new IntegerTIR(16), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("pow"),
			        new TupleTIR(new IntegerTIR(2), new IntegerTIR(4)))));
		assertEquals("-3^3", new IntegerTIR(-27), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("pow"),
			        new TupleTIR(new IntegerTIR(-3), new IntegerTIR(3)))));
		
		assertEquals("1! should be 1", new IntegerTIR(1), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("!"),
			        new TupleTIR(new IntegerTIR(1)))));
		assertEquals("2! should be 2", new IntegerTIR(2), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("!"),
			        new TupleTIR(new IntegerTIR(2)))));
		assertEquals("5! should be 120", new IntegerTIR(120), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("!"),
			        new TupleTIR(new IntegerTIR(5)))));
		assertEquals("6! should be 720", new IntegerTIR(720), myCalculator
			    .visitApplication(new ApplicationTIR(new IdentifierTIR("!"),
			        new TupleTIR(new IntegerTIR(6)))));
	}

}
